/*
  Author: Ionel Crisu - crisuionel@yahoo.com
  support@FlashExtended.com
*/
package com.flashextended.utils.movement.transformationtool
{
	import mx.core.UIComponent;	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Timer;
	
	import mx.core.UIComponent;
	
	public class Handler extends UIComponent
	{
		private var c0:UIComponent;
		private var c1:UIComponent;
		private var c2:UIComponent;
		private var c3:UIComponent;
		private var lines:UIComponent;
		private var body:UIComponent;
		
		private var reference:UIComponent;
		private var w:Number;
		private var h:Number;
		private var timer:Timer;
		private var doubleClickTimer:Timer;
		private var draggedObject:int;
		protected var col:uint;
		protected var cornerSize:Number;
		
		protected var doubleClicks:int = 0;
		
		//const
		private static var BRING_REFERENCE:String = "bringObject";
		
		private var initialRotationX:Number;
		private var initialRotationY:Number;
		private var bodyX:Number;
		private var bodyY:Number;
		private var linesX:Number;
		private var linesY:Number;
		private var c0X:Number;
		private var c0Y:Number;
		private var c1X:Number;
		private var c1Y:Number;
		private var c2X:Number;
		private var c2Y:Number;
		private var c3X:Number;
		private var c3Y:Number;	
				
		public function Handler(reference:UIComponent, w:Number, h:Number, col:uint=0x000000, cornerSize:Number=10)
		{
			super();
			this.w = w;
			this.h = h;
			this.reference = reference;
			this.rotation = reference.rotation;
			this.col = uint(col);
			this.cornerSize = cornerSize;
			timer = new Timer(10, 99999);
			timer.addEventListener(TimerEvent.TIMER, repeatEngine);
			doubleClickTimer = new Timer(900, 1);
			doubleClickTimer.addEventListener(TimerEvent.TIMER_COMPLETE, resetDoubleClick);			
			buildGraphics();
		}
		
		public function updateWH(w:Number, h:Number):void
		{
			this.w = w;
			this.h = h;
		}
		
		//Build graphics
		////////////////
		private function buildGraphics():void
		{
			c0 = buildButton("square", col, cornerSize, cornerSize);
			c1 = buildButton("circle", col, cornerSize/2, cornerSize/2);
			c2 = buildButton("square", col, cornerSize, cornerSize);
			c3 = buildButton("square", col, cornerSize, cornerSize);
			lines = new UIComponent();
			body = buildButton("square", 0xC15757, reference.width, reference.height, .2);
			body.alpha = 0;
			positionAll();
			this.x = reference.x;
			this.y = reference.y;
			this.width = reference.width;
			this.height = reference.height;
			this.addChild(body);
			this.addChild(lines);
			this.addChild(c0);
			this.addChild(c1);
			this.addChild(c2);
			this.addChild(c3);
			buttonsPress();
			buildLines();
		}
		private function buildButton(type:String = "square", col:uint=0x000000, w:Number=5, h:Number=5, alpha:Number=1):UIComponent
		{
			var ui:UIComponent = new UIComponent();
			var sp:Sprite = new Sprite();
			sp.name = "sp";
			sp.graphics.beginFill(col, 1);
			if(type == "square")
			{
				sp.graphics.drawRect(0, 0, w, h);
				ui.width = w;
				ui.height = h;
			}
			else
			{
				sp.graphics.drawCircle(0, 0, w);
				ui.width = w*2;
				ui.height = ui.width;				
			}
			sp.graphics.endFill();
			sp.alpha = alpha;
			ui.addChild(sp);
			ui.buttonMode = true;
			return ui;
		}
		private function buildLines():void
		{
			lines.graphics.clear();
			lines.graphics.lineStyle(1, this.col);
			lines.graphics.moveTo(c0.x+c0.width/2, c0.y+c0.height/2);
			lines.graphics.lineTo(c1.x, c1.y);
			lines.graphics.lineTo(c2.x+c2.width/2, c2.y+c2.height/2);
			lines.graphics.lineTo(c3.x+c3.width/2, c3.y+c2.height/2);
			lines.graphics.lineTo(c0.x+c0.width/2, c0.y+c0.height/2);
		}
		
		//Utils
		//////////////////
		private function position(ob:UIComponent, x1:Number=0, y1:Number=0):void
		{
			ob.x = x1;
			ob.y = y1;
		}
		private function positionAll():void
		{
			position(c0, -c0.width/2, -c0.height/2);
			position(c1, reference.width);
			position(c2, reference.width-c2.width/2, reference.height-c2.width/2);
			position(c3, 0-c3.width/2, reference.height-c2.width/2);
			position(body);
		}
		private function invisibleButtons(val:Boolean):void
		{
			c0.visible = val;
			c1.visible = val;
			c2.visible = val;
			c3.visible = val;
		}
		
		//Press Buttons
		//////////////////
		private function buttonsPress():void
		{
			c0.addEventListener(MouseEvent.MOUSE_DOWN, startDragButton0);
			c1.addEventListener(MouseEvent.MOUSE_DOWN, startDragButton1);
			c2.addEventListener(MouseEvent.MOUSE_DOWN, startDragButton2);
			c3.addEventListener(MouseEvent.MOUSE_DOWN, startDragButton3);
			body.addEventListener(MouseEvent.MOUSE_DOWN, startDragComponent);
			//
			c0.addEventListener(MouseEvent.MOUSE_UP, stopDragButton0);
			c1.addEventListener(MouseEvent.MOUSE_UP, stopDragButton1);
			c2.addEventListener(MouseEvent.MOUSE_UP, stopDragButton2);
			c3.addEventListener(MouseEvent.MOUSE_UP, stopDragButton3);
			body.addEventListener(MouseEvent.MOUSE_UP, stopDragComponent);
		}
		//Button listeners
		//////////////////
		private function startDragButton0(e:MouseEvent):void
		{
			body.alpha = .6;
			draggedObject = 0;
			initDragging();
			c0.startDrag(false, new Rectangle(-1000, -1000, 1000+c1.x-(c1.width+6), 1000+c3.y-(c3.width+3)));
		}
		private function stopDragButton0(e:MouseEvent):void
		{
			body.alpha = 0;
			c0.stopDrag();
			stopDragging();
		}
		private function startDragButton1(e:MouseEvent):void
		{
			body.alpha = .6;
			draggedObject = 1;
			initDragging();
			initialRotationX = this.reference.x;
			initialRotationY = this.reference.y;
			bodyX = body.x;
			bodyY = body.y;
			linesX = lines.x;
			linesY = lines.x;
			c0X = c0.x;
			c0Y = c0.y;
			c1X = c1.x;
			c1Y = c1.y;
			c2X = c2.x;
			c2Y = c2.y;
			c3X = c3.x;
			c3Y = c3.y;				
			//c1.startDrag(false, new Rectangle(c0.x+c0.width+3, -1000, 1000, c2.y-(c2.width+3)));
		}
		private function stopDragButton1(e:MouseEvent):void
		{
			body.alpha = 0;
			c1.stopDrag();
			stopDragging();
			removeRotation();
		}
		private function startDragButton2(e:MouseEvent):void
		{
			body.alpha = .6;
			draggedObject = 2;
			initDragging();
			c2.startDrag(false, new Rectangle(c0.width, c0.height, 1000, 1000));
		}
		private function stopDragButton2(e:MouseEvent):void
		{
			body.alpha = 0;
			c2.stopDrag();
			stopDragging();
		}		
		private function startDragButton3(e:MouseEvent):void
		{
			body.alpha = .6;
			draggedObject = 3;
			initDragging();
			c3.startDrag(false, new Rectangle(-1000, c0.height+3, 1000+c2.x-(c2.width+3), 1000));
		}
		private function stopDragButton3(e:MouseEvent):void
		{
			body.alpha = 0;
			c3.stopDrag();
			stopDragging();
		}
		////for body
		private function startDragComponent(e:MouseEvent):void
		{
			body.alpha = .6;
			doubleClickTimer.start();
			draggedObject = 4;
			timer.start();
			invisibleButtons(false);
			//this.startDrag(false, new Rectangle(0, 0, this.parent.width-this.width, this.parent.height-this.height));
			this.startDrag(false);
			stage.addEventListener(MouseEvent.MOUSE_UP, stopDragComponent);
			doubleClicks++;
			dispatchDoubleClick();
		}
		private function stopDragComponent(e:MouseEvent):void
		{
			body.alpha = 0;
			stopDragging();
			invisibleButtons(true);
			stage.removeEventListener(MouseEvent.MOUSE_UP, stopDragComponent);
		}
		//Timmer
		private function repeatEngine(e:TimerEvent):void
		{
			//trace("timer "+draggedObject);
			if(draggedObject == 1)
			{
				retriveAngle();
			}
			else
			{
				positionRealTimeButtons();
			}
		}
		
		private function applyRotation(ob:Object, initalX:Number, initialY:Number, normal:Boolean=false):void
		{

		}
		private function removeRotation():void
		{
		}
		
		//dispatch event
		private function initDragging():void
		{
			timer.start();
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleasedOutside);
		}
		private function mouseReleasedOutside(e:MouseEvent):void
		{
			stopDragging();
			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseReleasedOutside);
		}
		private function stopDragging():void
		{
			if(draggedObject == 1)
			{
				//this.removeRotation();
				//trace(this.rotation);
			}
						
			lines.graphics.clear();
			buildLines();
			this.stopDrag();
			timer.stop();
			var mainPX:Number = extractPoints()[0].x;
			var mainPY:Number = extractPoints()[0].y;
			if((draggedObject!=4) && (draggedObject!=1))
			{
				if(body.x<0)
				{
					var temp:Number = body.x;
					body.x=0;
					this.x+=temp;
					c0.x+=-temp;
					c1.x+=-temp;
					c2.x+=-temp;
					c3.x+=-temp;
				}
				if(body.x>0)
				{
					var temp3:Number = body.x;
					body.x=0;
					this.x+=temp3;
					c0.x-=temp3;
					c1.x-=temp3;
					c2.x-=temp3;
					c3.x-=temp3;
				}
				if(body.y<0)
				{
					var temp2:Number = body.y;
					body.y=0;
					this.y+=temp2;
					c0.y+=-temp2;
					c1.y+=-temp2;
					c2.y+=-temp2;
					c3.y+=-temp2;
				}
				if(body.y>0)
				{
					var temp4:Number = body.y;
					body.y=0;
					this.y+=temp4;
					c0.y-=temp4;
					c1.y-=temp4;
					c2.y-=temp4;
					c3.y-=temp4;
				}				
				reference.width = body.width;
				reference.height = body.height;
			}
			if(draggedObject == 1)
			{
				retriveAngle();
			}
			this.x = mainPX;
			this.y = mainPY;	
			this.dispatchEvent(new Event(BRING_REFERENCE));
		}
		
		private function extractPoints():Array
		{
			var po1:Point = new Point(c0.x+c0.width/2, c0.y+c0.height/2);
			po1 = this.localToGlobal(po1);
			var po11:Point = new Point(po1.x, po1.y);
			po11 = this.parent.globalToLocal(po11);
			var ar:Array = new Array();
			ar.push(po11);
			return ar;
		}
		
		//handle buttons real time positioning
		public function positionRealTimeButtons():void
		{
			if(draggedObject==0)
			{
				c3.x = c0.x;
				c1.y = c0.y+c1.height/2;
			}
			else if(draggedObject==2)
			{
				c1.x = c2.x+c1.width/2;
				c3.y = c2.y;
			}
			else if(draggedObject==3)
			{
				c0.x = c3.x;
				c2.y = c3.y;
			}
			buildLines();
			body.x = c0.x+c0.width/2;
			body.y = c0.y+c0.height/2;
			body.width = c1.x - c0.x-c0.width/2;
			body.height = c3.y - c0.y;
			body.getChildByName("sp").width = c1.x - c0.x-c0.width/2;
			body.getChildByName("sp").height = c3.y - c0.y;
			this.dispatchEvent(new Event("resized"));
		}
		
		public function retriveAngle():void
		{
			var adjside:Number = this.parent.mouseX - this.x;
			var oppside:Number = -1*(this.parent.mouseY - this.y);
			var angle:Number = Math.atan2(oppside, adjside);//in radians
			angle = Math.round(angle/Math.PI*180); // convert to degrees
			this.rotation = -1*(angle);
			reference.rotation = this.rotation;
			this.dispatchEvent(new Event("rotated"));
		}
		
		//dispatch double click event
		private function dispatchDoubleClick():void
		{
			if(doubleClicks>=2)
			{
				//stage.removeEventListener(MouseEvent.MOUSE_UP, stopDragComponent);
				this.dispatchEvent(new Event("doubleClick"));
			}
		}
		public function clearEvents():void
		{
			stage.removeEventListener(MouseEvent.MOUSE_UP, stopDragComponent);
		}
		private function resetDoubleClick(e:TimerEvent):void
		{
			//trace("resetTimer");
			doubleClicks = 0;
		}
		
		//used for text double click
		public function extraDoubleClick(val:Boolean):void
		{
			c0.visible = val;
			c1.visible = val;
			c2.visible = val;
			c3.visible = val;
			body.visible = val;	
		}		
		
	}
}